/* * Copyright (C) 2010 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.incad.kramerius.editor.client.view; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.logical.shared.HasCloseHandlers; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiConstructor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TabLayoutPanel; import com.google.gwt.user.client.ui.Widget; import cz.incad.kramerius.editor.client.EditorConstants; /** * Improves TabLayoutPanel with new features like tab close handle or * tab state presentation. * * <p>The composition instead of inheritance was chosen to be able to use * the class with UiBinder. Unfortunately it is not possible to declare * tab children in ui.xml now. * See <a href='http://code.google.com/p/google-web-toolkit/issues/detail?id=4342'> * gwt issue 4342</a> for details.</p> * * @author Jan Pokorsky */ public class AdvancedTabLayoutPanel extends Composite implements HasCloseHandlers<Integer> { private static final EditorConstants I18N = GWT.create(EditorConstants.class); private final TabLayoutPanel delegate; private int lastSelectedIndex = -1; public interface Resources extends ClientBundle { // @CssResource.NotStrict @Source("AdvancedTabLayoutPanel.css") Style css(); } public interface Style extends CssResource { String modified(); String tabCloseButton(); String tabCloseButtonSelected(); } private Style style; @UiConstructor public AdvancedTabLayoutPanel(String barHeight, String barUnit) { this(Double.parseDouble(barHeight), Unit.valueOf(barUnit)); } public AdvancedTabLayoutPanel(double barHeight, Unit barUnit) { TabLayoutPanelFactory factory = GWT.create(TabLayoutPanelFactory.class); delegate = factory.create(barHeight, barUnit); // delegate = new TabLayoutPanel(barHeight, barUnit); Resources bundle = GWT.<Resources>create(Resources.class); this.style = bundle.css(); this.style.ensureInjected(); initWidget(delegate); delegate.addSelectionHandler(new SelectionHandler<Integer>() { @Override public void onSelection(SelectionEvent<Integer> event) { int oldIndex = lastSelectedIndex; lastSelectedIndex = event.getSelectedItem(); followDelegateSelection(oldIndex, lastSelectedIndex); } }); } public void add(Widget child, String text, boolean closeable) { Widget advancedTab; if (closeable) { advancedTab = new AdvancedTab(text, createCloseTabWidget(child), style); } else { advancedTab = new AdvancedTab(text, style); } delegate.add(child, advancedTab); } public void insert(Widget child, String text, int beforeIndex, boolean closeable) { Widget advancedTab; if (closeable) { advancedTab = new AdvancedTab(text, createCloseTabWidget(child), style); } else { advancedTab = new AdvancedTab(text, style); } delegate.insert(child, advancedTab, beforeIndex); } /** * @see TabLayoutPanel#remove(int) */ public boolean remove(int index) { int selectedIndex = getSelectedIndex(); boolean removed = delegate.remove(index); if (removed) { reselectIfNecessary(index, selectedIndex); } return removed; } /** * @see TabLayoutPanel#remove(com.google.gwt.user.client.ui.Widget) */ public boolean remove(Widget w) { return delegate.remove(w); } /** * @see TabLayoutPanel#setTabText(int, java.lang.String) */ public void setTabText(int index, String text) { AdvancedTab tabWidget = AdvancedTab.get(delegate.getTabWidget(index)); tabWidget.setTabText(text); } @Override public HandlerRegistration addCloseHandler(CloseHandler<Integer> handler) { return addHandler(handler, CloseEvent.getType()); } public void setModified(int index, boolean modified) { AdvancedTab tabWidget = AdvancedTab.get(delegate.getTabWidget(index)); Widget tabLabel = tabWidget.getTabLabel(); if (modified) { tabLabel.getElement().addClassName(this.style.modified()); } else { tabLabel.getElement().removeClassName(this.style.modified()); } tabWidget.setModifiedTab(modified); } /** * @see TabLayoutPanel#getSelectedIndex() */ public int getSelectedIndex() { return delegate.getSelectedIndex(); } /** * @see TabLayoutPanel#selectTab(int) */ public void selectTab(int index) { delegate.selectTab(index); } /** * @see TabLayoutPanel#selectTab(com.google.gwt.user.client.ui.Widget) */ public void selectTab(Widget child) { delegate.selectTab(child); } /** * @see TabLayoutPanel#addSelectionHandler(com.google.gwt.event.logical.shared.SelectionHandler) */ public HandlerRegistration addSelectionHandler(SelectionHandler<Integer> handler) { return delegate.addSelectionHandler(handler); } private void followDelegateSelection(int oldIndex, int newIndex) { if (oldIndex >= 0 && oldIndex < delegate.getWidgetCount()) { AdvancedTab tabWidget = AdvancedTab.get(delegate.getTabWidget(oldIndex)); tabWidget.setSelected(false); } AdvancedTab tabWidget = AdvancedTab.get(delegate.getTabWidget(newIndex)); tabWidget.setSelected(true); } /** * It is necessary to adjust tab selection as TabLayoutPanel.remove always * selects index 0 when index == selectedIndex * * @param removedIndex removed tab * @param selectedIndex tab selected before remove */ private void reselectIfNecessary(int removedIndex, int selectedIndex) { int select = -1; if (removedIndex == selectedIndex) { if (selectedIndex > 0) { select = selectedIndex - 1; } else if (delegate.getWidgetCount() > 0) { // ignore // select = 0; } } else { // ignore // select = selectedIndex < removedIndex ? selectedIndex : selectedIndex - 1; } if (select >= 0) { delegate.selectTab(select); } } private Widget createCloseTabWidget(final Widget child) { Label closeHandle = new InlineLabel(); closeHandle.setTitle(I18N.closeTabHandleTooltip()); closeHandle.addStyleName("ui-icon ui-icon-close"); closeHandle.addStyleName(this.style.tabCloseButton()); closeHandle.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int widgetIndex = delegate.getWidgetIndex(child); CloseEvent.fire(AdvancedTabLayoutPanel.this, widgetIndex, false); } }); return closeHandle; } /** * do not extend FlowPanel as it does not work with IE7 and older */ private static final class AdvancedTab extends HorizontalPanel { private final Label label; private final Widget closer; private boolean modified; private final Style style; public AdvancedTab(String text, Style style) { this(text, null, style); } public AdvancedTab(String text, Widget closer, Style style) { this.label = new InlineLabel(ViewUtils.makeLabelVisible(text)); this.label.setTitle(text); add(this.label); this.closer = closer; if (closer != null) { add(closer); } this.style = style; } public Widget getTabLabel() { return label; } public Widget getTabCloser() { return closer; } public boolean isModifiedTab() { return modified; } public void setModifiedTab(boolean modified) { this.modified = modified; } public void setSelected(boolean selected) { if (closer != null) { if (selected) { closer.addStyleName(style.tabCloseButtonSelected()); } else { closer.removeStyleName(style.tabCloseButtonSelected()); } } } private void setTabText(String text) { this.label.setText(ViewUtils.makeLabelVisible(text)); this.label.setTitle(text); } public static AdvancedTab get(Widget tabWidget) { return (AdvancedTab) tabWidget; } } }